package com.zjw.zy.heart.wbsocket.socket;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.zjw.zy.heart.utils.JsonUtils;
import lombok.Data;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import org.json.JSONObject;

import java.io.Serializable;
import java.util.*;

@Getter
@Setter
public class WsMessage implements Serializable {

    public static final String BIND_LOVE_INFO = "BIND_LOVE_INFO?";
    public static final String WECHAT_MESSAGE_INFO = "WECHAT_MESSAGE_INFO?";
    public static final String WECHAT_MESSAGE_SYNC_INFO = "WECHAT_MESSAGE_SYNC_INFO?";
    public static final String WECHAT_MESSAGE_PULL_INFO = "WECHAT_MESSAGE_PULL_INFO?";
    public static final String CLIENT_TO_CLIENT_INFO = "CLIENT_TO_CLIENT_INFO?";
    public static final String CLIENT_TO_CLIENT_FAIL_INFO = "CLIENT_TO_CLIENT_FAIL_INFO?";
    public static final String CLIENT_TO_CLIENT_STRONG_INFO = "CLIENT_TO_CLIENT_STRONG_INFO?";
    public static final String CLIENT_TO_CLIENT_STRONG_CACHE_INFO = "CLIENT_TO_CLIENT_STRONG_CACHE_INFO?";
    private static final Queue<WsMessage> sCacheMessagePool = new LinkedList<>();
    private static final int MAX_CACHE_COUNT = 1000;
    @JsonProperty("id")
    private Long id = -1L;
    @JsonProperty("from")
    private String from = "";
    @JsonProperty("to")
    private String to = "";
    @JsonProperty("text")
    private String text = "";
    @JsonProperty("date")
    private Long date = 0L;
    @JsonProperty("info")
    private String info = "";
    @JsonIgnore
    private transient Object payload;

    public WsMessage() {
    }

    public WsMessage(String info) {
        this.info = info;
    }

    public void jsonPayload() {
        this.text = JsonUtils.toJson(payload == null ? "" : payload);
    }

    @SuppressWarnings("unchecked")
    public <T> T getPayload(Class<T> clazz) {
        return (T) (this.payload = JsonUtils.fromJson(text, clazz));
    }

    public void setPayload(Object payload) {
        this.payload = payload;
    }

    /**
     * 提高性能
     */
    @NonNull
    public static WsMessage obtainFromString(String message) {
        WsMessage obtain = obtain();

        JSONObject object = new JSONObject(message);

        obtain.id = object.optLong("id");
        obtain.from = object.optString("from");
        obtain.to = object.optString("to");
        obtain.text = object.optString("text");
        obtain.date = object.optLong("date");
        obtain.info = object.optString("info");

        return obtain;
    }

    public static WsMessage obtain() {
        synchronized (sCacheMessagePool) {
            if (sCacheMessagePool.isEmpty()) {
                return new WsMessage();
            } else {
                return sCacheMessagePool.poll();
            }
        }
    }

    public static WsMessage obtain(String info) {
        WsMessage obtain = obtain();
        obtain.info = info;
        obtain.date = System.currentTimeMillis();
        return obtain;
    }

    public void recycle() {
        reset();
        synchronized (sCacheMessagePool) {
            if (sCacheMessagePool.size() >= MAX_CACHE_COUNT) {
                return;
            }
            sCacheMessagePool.offer(this);
        }
    }

    public String toJson() {
        JSONObject object = new JSONObject();
        object.put("id", id);
        object.put("from", from);
        object.put("to", to);
        object.put("text", text);
        object.put("info", info);
        object.put("date", date);

        return object.toString();
    }


    private void reset() {
        this.info = "";
        this.text = "";
        this.payload = null;
        this.id = -1L;
        this.date = -1L;
        this.from = "";
        this.to = "";
    }

    @Override
    public String toString() {
        return "WsMessage{" +
                "id=" + id +
                ", from='" + from + '\'' +
                ", to='" + to + '\'' +
                ", date=" + date +
                ", info='" + info + '\'' +
                '}';
    }
}
